import { Injectable } from '@nestjs/common';
import { isNil, omit } from 'lodash';
import {
    DataSource, FindManyOptions, DeleteResult
} from 'typeorm';

import { InjectDataSource } from '@nestjs/typeorm';
import {
    CreateMenuActionDto,
    CreateSysActionDto,
    CreateySysMenuDto,
    GetActionsByMenuDto,
    MoveSysMenuDto,
    UpdatePwDto,
} from './dto/create-sy.dto';
import { UpdateSysActionDto, UpdateSysMenuDto } from './dto/update-sy.dto';
import {
    SysUser,
    SysMenu,
    SysAction, SysMenuAction
} from './entities/sys.entity';
import { ResponseJson } from '@/common/type/app.dto';
import { ResponseCode } from '@/common/type/enum';
import { DeleteDto } from '@/common/type/app.dto';
import { OrderTree, orderTree } from '@/common/tool/treehelper';
import { SysRoleMenuAction, SysRoleMenu } from '@/auth/entities/auth.entity';
@Injectable()
export class SysService {
    constructor(
        @InjectDataSource() private datasource: DataSource,
    ) { }
  
    async createSysMenu(sysMenu: CreateySysMenuDto): Promise<ResponseJson<SysMenu, null>> {
        const sysMenuObj = this.datasource.manager.create<SysMenu>(
            SysMenu,
            sysMenu,
        );
        if (!isNil(sysMenu.parentId)) {
            const parent = await this.datasource.manager.findOne<SysMenu>(
                SysMenu,
                {
                    where: {
                        id: sysMenu.parentId,
                    },
                },
            );
            sysMenuObj.parent = parent;
        }
        const r = await this.datasource.manager.save<SysMenu>(sysMenuObj);
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: r,
        };
    }
    async updateSysMenu(sysMenu: UpdateSysMenuDto): Promise<ResponseJson<null, null>> {
        const parent = isNil(sysMenu.parentId)
            ? null
            : await this.datasource.manager.findOne<SysMenu>(SysMenu, {
                where: {
                    id: sysMenu.parentId,
                },
            });
        const oldSysMenu = await this.datasource.manager.preload<SysMenu>(
            SysMenu,
            omit(sysMenu, ['parentId']),
        );
        oldSysMenu.parent = parent;
        const r = await this.datasource.manager.save<SysMenu>(oldSysMenu);
        return {
            code: ResponseCode.SuccessWithSuc,
            msg: ['修改成功'],
        };
    }
    async getMenuTree(): Promise<ResponseJson<OrderTree[], null>> {
        const tree = await this.datasource.manager
            .getTreeRepository(SysMenu)
            .findTrees();
        // console.log(tree);
        
        const newtree = orderTree(tree);
        // console.log(newtree);
        
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: newtree,
        };
    }

    async deleteSysMenu(ids: DeleteDto): Promise<ResponseJson<null, null>> {
        let r: DeleteResult;
        const queryRunner = this.datasource.createQueryRunner();

        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            if (ids.ids.length === 1) {
                await queryRunner.manager.createQueryBuilder<SysRoleMenuAction>(SysRoleMenuAction, 'sys_rolemenuaction').delete()
                    .from(SysRoleMenuAction).where('menuId = :menuId', { menuId: ids.ids[0] }).execute();
                await queryRunner.manager.createQueryBuilder<SysMenuAction>(SysMenuAction, 'sys_menuaction').delete()
                    .from(SysMenuAction).where('menuId = :menuId', { menuId: ids.ids[0] }).execute();
                await queryRunner.manager.createQueryBuilder<SysRoleMenu>(SysRoleMenu, 'sys_rolemenu').delete()
                    .from(SysRoleMenu).where('menuId = :menuId', { menuId: ids.ids[0] }).execute();
                r = await queryRunner.manager.createQueryBuilder<SysMenu>(SysMenu, 'sys_menu').delete()
                    .from(SysMenu).where('id = :id', { id: ids.ids[0] }).execute();
            } else {
                await queryRunner.manager.createQueryBuilder<SysRoleMenuAction>(SysRoleMenuAction, 'sys_rolemenuaction').delete()
                    .from(SysRoleMenuAction).where('menuId in (:...menuId)', { menuId: ids.ids }).execute();
                await queryRunner.manager.createQueryBuilder<SysMenuAction>(SysMenuAction, 'sys_menuaction').delete()
                    .from(SysMenuAction).where('menuId in (:...menuId)', { menuId: ids.ids }).execute();
                await queryRunner.manager.createQueryBuilder<SysRoleMenu>(SysRoleMenu, 'sys_rolemenu').delete()
                    .from(SysRoleMenu).where('menuId in (:...menuId)', { menuId: ids.ids }).execute();
                r = await queryRunner.manager.createQueryBuilder<SysMenu>(SysMenu, 'sys_menu').delete()
                    .from(SysMenu).where('id in (:...ids)', { ids: ids.ids }).execute();
            }
            await queryRunner.commitTransaction();
        } catch (err) {
            await queryRunner.rollbackTransaction();
        } finally {
            await queryRunner.release();
        }

        if (r) {
            return {
                code: ResponseCode.SuccessWithSuc,
                msg: [`删除${r.affected}条记录`],
            };
        } else {
            return {
                code: ResponseCode.FailWithMsg,
                msg: [`删除失败`],
            };
        }
    }

    async moveSysMenu(moveDto: MoveSysMenuDto): Promise<ResponseJson<null, null>> {
        const menu = await this.datasource.manager.findOne<SysMenu>(SysMenu, {
            where: {
                id: moveDto.id,
            },
            relations: ['parent'],
        });
        const parent = await this.datasource.manager.findOne<SysMenu>(SysMenu, {
            where: {
                id: moveDto.parent_id,
            },
        });

        if (
            (isNil(menu.parent) && isNil(moveDto.parent_id)) ||
            menu.parent?.id === moveDto.parent_id
        ) {
            return {
                code: ResponseCode.SuccessNoMsg,
            };
        }
        menu.parent = parent;
        const r = await this.datasource.manager.save<SysMenu>(menu);
        return {
            code: ResponseCode.SuccessWithInfo,
            msg: ['保存成功'],
        };
    }
    async getActions(query: FindManyOptions<SysAction>): Promise<ResponseJson<SysAction[], number>> {

        const [actions, actionsCount] =
            await this.datasource.manager.findAndCount<SysAction>(
                SysAction,
                query,
            );
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: actions,
            ext: actionsCount,
        };
    }
    async createAction(actionDto: CreateSysActionDto): Promise<ResponseJson<SysAction, null>> {
        const sysActionObj = this.datasource.manager.create<SysAction>(
            SysAction,
            actionDto,
        );

        const r = await this.datasource.manager.save<SysAction>(sysActionObj);
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: r,
        };
    }

    async updateAction(actionDto: UpdateSysActionDto): Promise<ResponseJson<null, null>> {
        const result = await this.datasource.manager.update<SysAction>(
            SysAction,
            { id: actionDto.id },
            omit(actionDto, ['id']),
        );        
        return {
            code:
                result.affected === 1
                    ? ResponseCode.SuccessNoMsg
                    : ResponseCode.FailWithMsg,
//             obj: [],
            msg: result.affected === 1 ? [] : ['修改失败'],
        };
    }
    async deleteAction(dto: DeleteDto): Promise<ResponseJson<null, null>> {
        let r: DeleteResult;
        const queryRunner = this.datasource.createQueryRunner();

        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            if (dto.ids.length === 1) {
                await queryRunner.manager.createQueryBuilder<SysMenuAction>(SysMenuAction, 'sys_menuaction').delete()
                    .from(SysMenuAction).where('actionId = :actionId', { actionId: dto.ids[0] }).execute();
                await queryRunner.manager.createQueryBuilder<SysRoleMenuAction>(SysRoleMenuAction, 'sys_roleaction').delete()
                    .from(SysRoleMenuAction).where('actionId = :actionId', { actionId: dto.ids[0] }).execute();

                r = await queryRunner.manager.createQueryBuilder<SysAction>(SysAction, 'sys_action').delete()
                    .from(SysAction).where('id = :id', { id: dto.ids[0] }).execute();
            } else {
                await queryRunner.manager.createQueryBuilder<SysMenuAction>(SysMenuAction, 'sys_menuaction').delete()
                    .from(SysMenuAction).where('actionId in (:...actionId)', { actionId: dto.ids }).execute();
                await queryRunner.manager.createQueryBuilder<SysRoleMenuAction>(SysRoleMenuAction, 'sys_roleaction').delete()
                    .from(SysRoleMenuAction).where('actionId in (:...actionId)', { actionId: dto.ids }).execute();
                r = await queryRunner.manager.createQueryBuilder<SysAction>(SysAction, 'sys_action').delete()
                    .from(SysAction).where('id in (:...ids)', { ids: dto.ids }).execute();
            }
            await queryRunner.commitTransaction();
        } catch (err) {
            await queryRunner.rollbackTransaction();
        } finally {
            await queryRunner.release();
        }

        if (r) {
            return {
                code: ResponseCode.SuccessWithSuc,
                msg: [`删除${r.affected}条记录`],
            };
        } else {
            return {
                code: ResponseCode.FailWithMsg,
                msg: [`删除失败`],
            };
        }
    }


    async getActionsByMenu(dto: GetActionsByMenuDto): Promise<ResponseJson<SysMenuAction[], null>> {
        const actions = await this.datasource.manager.find<SysMenuAction>(
            SysMenuAction,
            {
                where: {
                    menu: {
                        id: dto.menuId,
                    },
                },
                relations: {
                    action: true,
                },
                select: {
                    id: true,
                    remark: true,
                    action: {
                        id: true,
                        label: true,
                        url: true,
                    }
                },
            },
        );
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: actions,
        };
    }
    /**
     * 查询sys_,menuaction中没有和传入menu绑定的actions
     */
    async getActionsByUnLinkMenu(dto: GetActionsByMenuDto): Promise<ResponseJson<SysAction[], null>> {
        const menuId = dto.menuId;
        const unLinkedActions = await this.datasource.getRepository(SysAction).createQueryBuilder("action").where((qb) => {
            const subQuery = qb.subQuery()
                .select("menuaction.action.id", "id")
                .from(SysMenuAction, "menuaction")
                .where("menuaction.menu.id = :menuId")
                .setParameter("menuId", menuId)
                .getQuery();
            return "action.id not IN" + subQuery;
        }).getMany();

        return {
            code: ResponseCode.SuccessNoMsg,
            obj: unLinkedActions
        };
    }
    async createMenuActions(dto: CreateMenuActionDto[]): Promise<ResponseJson<null, null>> {
        const result = await this.datasource
            .createQueryBuilder()
            .insert()
            .into(SysMenuAction)
            .values(dto as Partial<SysMenuAction>)
            .execute();
        return {
            code: ResponseCode.SuccessNoMsg,
        }
    }
    async deleteMenuActions(dto: DeleteDto): Promise<ResponseJson<null, null>> {
        let result: DeleteResult;
        if (dto.ids.length === 1) {
            result = await this.datasource.createQueryBuilder(SysAction, 'menuaction')
                .delete()
                .from(SysMenuAction)
                .where('id = :id', { id: dto.ids[0] })
                .execute();
        } else {
            result = await this.datasource.createQueryBuilder(SysMenuAction, 'menuaction')
                .delete()
                .from(SysMenuAction)
                .whereInIds(dto.ids)
                .execute();
        }
        return {
            code:
                result.affected > 0
                    ? ResponseCode.SuccessWithInfo
                    : ResponseCode.ErrorWithMsg,
            msg: [`删除${result.affected}条记录`],
        };
    }
}
